#include "GGameObject.h"

namespace GEngine
{
	GGameObject::GGameObject()
	{
		Active = true;
		Hidden = false;
		Static = true;

		Name = "Unnamed game object";
		Parent = NULL;

		VisitorMask.RaiseAll();
	}

	GGameObject::~GGameObject()
	{
	}

	void GGameObject::OnChildAppend(GGameObject* NewChild)
	{
	}

	void GGameObject::OnChildRemove(GGameObject* OldChild)
	{
	}

	void GGameObject::OnParentChange(GGameObject* NewParent)
	{
	}

	void GGameObject::SetActive(bool Value)
	{
		Active = Value;
	}

	bool GGameObject::GetActive() const
	{
		return Active;
	}
		
	void GGameObject::SetHidden(bool Value)
	{
		Hidden = Value;
	}

	bool GGameObject::GetHidden() const
	{
		return Hidden;
	}

	void GGameObject::SetStatic(bool Value)
	{
		Static = Value;
	}

	bool GGameObject::GetStatic() const
	{
		return Static;
	}
		
	void GGameObject::SetName(const char* String)
	{
		Name = String;
	}

	const char* GGameObject::GetName() const
	{
		return Name.c_str();
	}

	// Component methods
	void GGameObject::ClearComponents()
	{
		GSize CompCount = Components.size();
		for (GSize I = 0; I < CompCount; ++I)
		{
			GComponent* ToRemove = Components.back();
			Components.pop_back();

			ToRemove->OnDetach();
		}
	}
	
	void GGameObject::RemoveComponent(const char* Name)
	{
		//! Brute force name search ?
	}

	void GGameObject::RemoveComponent(GComponent* Comp)
	{
		GSize I = 0;
		GSize CompCount = Components.size();
		for ( ; (I < CompCount) && (Components[I] != Comp); ++I)
		{
		}

		if (I == CompCount)
		{
			// No such component
			return;
		}

		GComponent* ToRemove = Components[I];
		Components[I] = Components.back();
		
		Components.pop_back();

		ToRemove->OnDetach();
	}
	
	bool GGameObject::ReplaceComponent(GComponent* NewComp, const char* OldComp)
	{
		//! Brute force name search ?
		return false;
	}

	bool GGameObject::ReplaceComponent(GComponent* NewComp, GComponent* OldComp)
	{
		GSize I = 0;
		GSize CompCount = Components.size();
		for ( ; (I < CompCount) && (Components[I] != OldComp); ++I)
		{
		}

		if (I == CompCount)
		{
			// No such component
			return false;
		}

		Components[I] = NewComp;

		NewComp->OnAtach();
		OldComp->OnDetach();

		return true;
	}
	
	void GGameObject::AppendComponent(GComponent* Comp)
	{
		Components.push_back(Comp);
		Comp->OnAtach();
	}

	template<typename T>
	T* GGameObject::FindComponent() const
	{
		//! rtti search ?
		return NULL;
	}

	GComponent* GGameObject::FindComponent(const char* Name) const
	{
		//! Brute force name search ?
		return NULL;
	}

	// Graph methods
	void GGameObject::SetVisitorMask(GUtil::GMask Mask)
	{
		VisitorMask = Mask;
	}

	GUtil::GMask GGameObject::GetVisitorMask() const
	{
		return VisitorMask;
	}
		
	GGameObject* GGameObject::GetParent() const
	{
		return Parent;
	}

	GUInt32 GGameObject::GetChildCount() const
	{
		return Children.size();
	}

	GGameObject* GGameObject::FindRoot() const
	{
		const GGameObject* Next = this;
		for (; Next->Parent != NULL; Next = Next->Parent)
		{
		}
		
		return const_cast<GGameObject*>(Next);
	}

	//! only search my children, do not go deeper in the tree
	GGameObject* GGameObject::FindChild(const char* Name) const
	{
		//! Brute force name search ?
		return NULL;
	}

	void GGameObject::RemoveChild(GGameObject* Child)
	{
		GSize I = 0;
		GSize ChildCount = Children.size();
		for ( ; (I < ChildCount) && (Children[I] != Child); ++I)
		{
		}

		if (I == ChildCount)
		{
			// No such component
			return;
		}

		GGameObject* ToRemove = Children[I];
		Children[I] = Children.back();
		Children.pop_back();

		OnChildRemove(ToRemove);
		ToRemove->OnParentChange(NULL);
	}

	void GGameObject::AppendChild(GGameObject* Child)
	{
		Children.push_back(Child);

		OnChildAppend(Child);
		Child->OnParentChange(this);
	}

	bool GGameObject::ReplaceChild(GGameObject* NewChild, GGameObject* OldChild)
	{
		GSize I = 0;
		GSize ChildCount = Children.size();
		for ( ; (I < ChildCount) && (Children[I] != OldChild); ++I)
		{
		}

		if (I == ChildCount)
		{
			// No such component
			return false;
		}

		Children[I] = NewChild;

		OnChildAppend(NewChild);
		NewChild->OnParentChange(this);

		OnChildRemove(OldChild);
		OldChild->OnParentChange(NULL);

		return true;
	}


}; // namespace GScene